﻿using UnityEngine;

// 继承后处理基类
public class MotionBlur : PostEffectsBase
{
    // 运动模糊使用的Shader
    public Shader motionBlurShader;

    // 运动模糊使用的材质
    private Material motionBlurMaterial = null;
    public Material material
    {
        get
        {
            motionBlurMaterial = CheckShaderAndCreateMaterial(motionBlurShader, motionBlurMaterial);
            return motionBlurMaterial;
        }
    }

    // 控制模糊拖尾效果，数值越大，效果越明显
    // 为了防止拖尾效果完全替代当前帧的渲染结果，将值的范围定在0.0~0.9
    [Range(0.0f, 0.9f)]
    public float blurAmount = 0.5f;

    // 借助RenderTexture（下称：“RT”）将前后的图像叠加在一起
    private RenderTexture accumulationTexture;

    // 脚本不运行时（即调用OnDisable函数），立即销毁accumulationTexture
    private void OnDisable()
    {
        DestroyImmediate(accumulationTexture);
    }

    private void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        if (material != null)
        {
            int width = source.width;
            int height = source.height;

            // 当RT的纹理不满足当前需要的尺寸时，销毁并重新生成一个RT
            if (accumulationTexture == null || accumulationTexture.width != width || accumulationTexture.height != height)
            {
                // 立即销毁RT
                DestroyImmediate(accumulationTexture);
                // 生成满足宽高的RT
                accumulationTexture = new RenderTexture(width, height, 0);
                // 因为这个变量需要我们自己控制它的销毁，所以hideFlags设置为HideAndDontSave，
                // 意味着这个变量不会显示在Hierarchy中，也不会保存到场景中
                accumulationTexture.hideFlags = HideFlags.HideAndDontSave;
                // 将场景渲染的图像渲染到RT中
                Graphics.Blit(source, accumulationTexture);
            }

            // 表明需要进行一个渲染纹理的恢复操作
            // 恢复操作：发生在渲染到纹理而该纹理又没有被提前清空或销毁的情况下
            // 因为需要将当前帧的图像和之前的图形做混合，所以不需要提前清空accumulationTexture
            accumulationTexture.MarkRestoreExpected();

            material.SetFloat("_BlurAmount", 1.0f - blurAmount);

            // 将当前帧的图像纹理，叠加上前面帧渲染的图形一起渲染到RT上
            Graphics.Blit(source, accumulationTexture, material);
            // 将RT上的图像渲染到屏幕
            Graphics.Blit(accumulationTexture, destination);
        }
        else
        {
            Graphics.Blit(source, destination);
        }
    }
}
